#include "ComponentListModel.h"

#include "StringFormatter.h"

#include "LeIpc2581/Component.h"
#include "LeIpc2581/enumtranslator.h"

#include <QModelIndex>
#include <QTransform>
#include <QPointF>

struct ComponentItem
{
    ComponentItem():
        component(nullptr)
    {}

    explicit ComponentItem(const Ipc2581b::Component *component):
        component(component)
    {}

    const Ipc2581b::Component *component;
};

class ComponentListModelPrivate
{
    Q_DISABLE_COPY(ComponentListModelPrivate)
    Q_DECLARE_PUBLIC(ComponentListModel)
    ComponentListModel * const q_ptr;

    explicit ComponentListModelPrivate(ComponentListModel *model):
        q_ptr(model)
    {}

    QList<ComponentItem> m_data;

    inline void clear()
    {
        m_data.clear();
    }
};

ComponentListModel::ComponentListModel(QObject *parent):
    QAbstractTableModel(parent),
    d_ptr(new ComponentListModelPrivate(this))
{
}

ComponentListModel::~ComponentListModel()
{

}

void ComponentListModel::addComponent(const Ipc2581b::Component *component)
{
    Q_D(ComponentListModel);

    d->m_data.append(ComponentItem(component));
}

const Ipc2581b::Component *ComponentListModel::component(const QModelIndex &index) const
{
    Q_D(const ComponentListModel);

    if (!index.isValid())
        return nullptr;

    return d->m_data.value(index.row()).component;
}

void ComponentListModel::clear()
{
    Q_D(ComponentListModel);

    beginResetModel();
    d->clear();
    endResetModel();
}

int ComponentListModel::rowCount(const QModelIndex &parent) const
{
    Q_D(const ComponentListModel);

    if (parent.isValid())
        return 0;

    return d->m_data.count();
}

int ComponentListModel::columnCount(const QModelIndex &parent) const
{
    if (parent.isValid())
        return 0;

    return ColumnCount;
}

QVariant ComponentListModel::headerData(int section, Qt::Orientation orientation, int role) const
{
    if (orientation != Qt::Horizontal)
        return QVariant();

    if (role != Qt::DisplayRole)
        return QVariant();

    switch (section) {
        case NameColumn:
            return "Name";
        case PackageRefColumn:
            return "Package";
        case PartRefColumn:
            return "Part";
        case LayerRefColumn:
            return "Layer";
        case MountTypeColumn:
            return "Mount type";
        case WeightCoolumn:
            return "Weight";
        case HeightColumn:
            return "Height";
        case StandOffColumn:
            return "Stand off";
        case TransformColumn:
            return "Transform";
        case LocationColumn:
            return "Location";
        default:
            return QVariant();
    }
}

QVariant ComponentListModel::data(const QModelIndex &index, int role) const
{    
    Q_D(const ComponentListModel);

    if (!index.isValid())
        return QVariant();

    if (index.row() < 0 || index.row() >= rowCount())
        return QVariant();

    const Ipc2581b::Component *component = d->m_data.value(index.row()).component;
    switch (role)
    {
        case Qt::DisplayRole:
            switch (index.column())
            {
                case NameColumn:
                    return component->refDes;
                case PackageRefColumn:
                    return component->packageRef;
                case PartRefColumn:
                    return component->part;
                case LayerRefColumn:
                    return component->layerRef;
                case MountTypeColumn:
                    return Ipc2581b::EnumTranslator::mountText(component->mountType);
                case WeightCoolumn:
                    if (component->weightOptional.hasValue)
                        return component->weightOptional.value;
                    return QVariant();
                case HeightColumn:
                    if (component->heightOptional.hasValue)
                        return component->heightOptional.value;
                    return QVariant();
                case StandOffColumn:
                    if (component->standoffOptional.hasValue)
                        return component->standoffOptional.value;
                    return QVariant();
                case TransformColumn:
                    if (component->xformOptional.hasValue)
                        return StringFormatter::transform(component->xformOptional.value);
                    return QVariant();
                case LocationColumn:
                    return StringFormatter::pointF(component->location);
                default:
                    return QVariant();
            }
            break;
        case Qt::EditRole:
            switch (index.column())
            {
                case NameColumn:
                    return component->refDes;
                case PackageRefColumn:
                    return component->packageRef;
                case PartRefColumn:
                    return component->part;
                case LayerRefColumn:
                    return component->layerRef;
                case MountTypeColumn:
                    return QVariant::fromValue<Ipc2581b::Mount>(component->mountType);
                case WeightCoolumn:
                    if (component->weightOptional.hasValue)
                        return component->weightOptional.value;
                    return QVariant();
                case HeightColumn:
                    if (component->heightOptional.hasValue)
                        return component->heightOptional.value;
                    return QVariant();
                case StandOffColumn:
                    if (component->standoffOptional.hasValue)
                        return component->standoffOptional.value;
                    return QVariant();
                case TransformColumn:
                {
                    QTransform transform;
                    if (component->xformOptional.hasValue)
                        transform = createTransform(component->xformOptional.value);
                    return QVariant::fromValue<QTransform>(transform);
                }
                case LocationColumn:
                    return QVariant(QPointF(component->location->x, component->location->y));
                default:
                    return QVariant();
            }
        default:
            return QVariant();
    }
}
